using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace Terra.Data.Entities;

/// <summary>
/// 实体基类
/// </summary>
/// <typeparam name="TKey">主键类型</typeparam>
public abstract class EntityBase<TKey> : IEntity<TKey>
{
    /// <summary>
    /// 主键
    /// </summary>
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public TKey Id { get; set; }

    /// <summary>
    /// 判断实体是否为临时状态
    /// </summary>
    /// <returns></returns>
    public virtual bool IsTransient()
    {
        if (EqualityComparer<TKey>.Default.Equals(Id, default))
            return true;

        // 对于字符串类型的主键，空字符串也视为临时状态
        if (typeof(TKey) == typeof(string))
            return string.IsNullOrEmpty((string)(object)Id);

        if (typeof(TKey) == typeof(int))
            return Convert.ToInt32(Id) <= 0;

        if (typeof(TKey) == typeof(long))
            return Convert.ToInt64(Id) <= 0;

        return false;
    }

    /// <summary>
    /// 重写相等运算符
    /// </summary>
    public static bool operator ==(EntityBase<TKey> left, EntityBase<TKey> right)
    {
        if (Equals(left, null))
            return Equals(right, null);
        return left.Equals(right);
    }

    /// <summary>
    /// 重写不等运算符
    /// </summary>
    public static bool operator !=(EntityBase<TKey> left, EntityBase<TKey> right)
    {
        return !(left == right);
    }

    /// <summary>
    /// 重写相等比较
    /// </summary>
    public override bool Equals(object obj)
    {
        if (obj == null || !(obj is EntityBase<TKey>))
            return false;

        if (ReferenceEquals(this, obj))
            return true;

        if (GetType() != obj.GetType())
            return false;

        var item = (EntityBase<TKey>)obj;

        if (item.IsTransient() || IsTransient())
            return false;

        return EqualityComparer<TKey>.Default.Equals(Id, item.Id);
    }

    /// <summary>
    /// 重写获取哈希码
    /// </summary>
    public override int GetHashCode()
    {
        if (!IsTransient())
        {
            return Id.GetHashCode() ^ 31;
        }
        return base.GetHashCode();
    }

    /// <summary>
    /// 转换为字符串
    /// </summary>
    public override string ToString()
    {
        return $"[{GetType().Name} {Id}]";
    }
}